vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件

CommTable.vue table组件

<template>
  <div>
    <el-table
      :data="tableData"
      border
      :class="tabClass ? tabClass : null"
      :showHeader="showHeader ? showHeader : true"
      :spanMethod="spanMethod ? spanMethod : null"
      element-loading-text="加载中..."
      v-loading="loading"
      :height="height ? height : null"
      :maxHeight="maxHeight ? maxHeight : null"
      :ref="tabRef ? tabRef : null"
      :header-cell-style="smallRow ? lineStyle : null"
      :cell-style="smallRow ? lineStyle : null"
      @sort-change="sortByKey"
      @selection-change="selectionChange"
      :row-key="rowKey ? rowKey : null"
    >
      <!-- 详情内容展示 需要showExpand属性  -->
      <el-table-column type="expand" v-if="showExpand">
        <template slot-scope="{ row }">
          <slot name="expand" :data="row"></slot>
        </template>
      </el-table-column>
      <!-- checkout复选框  selectionObj对象 {show: true, fixed: true}-->
      <el-table-column type="selection" align="center" width="50" v-if="selectionObj.show" :fixed="selectionObj.fixed ? true : false ">
      </el-table-column>
      <el-table-column
        v-for="({ prop, label, width, minWidth ,sortBy, slotName, countLimit, childrenList, className, columnFlag, fixed }, index) in tablecolumn"
        :key="index"
        :prop="prop ? prop : null"
        :label="label ? label : null"
        :width="width ? width : null"
        :min-width="minWidth ? minWidth : 100"
        :sort-by="sortBy ? sortBy : null"
        :sortable="sortBy ? (columnFlag ? 'column' : true) : null"
        :className="className ? className : null"
        :fixed="fixed ? fixed : null"
        :render-header="renderHeader ? renderHeader : null"
        align="center"
      >
      <!-- 自定义表头 -->
      <template  slot="header" >
        <slot v-if="slotName" :name="slotName+'Header'" ></slot>
      </template>
      <!-- 自定义内容 -->
      <template v-if="!childrenList" slot-scope="{row, $index}">
        <!-- 自定义tamplate -->
        <!-- prop没有值的情况 传整个row -->
        <div  v-if="slotName" >
          <slot :name="slotName" :data="prop ? row[prop] : null" :index="$index" :rowData="row"></slot>
        </div>
        <!-- 字数(countLimit控制)超出显示tip -->
        <div v-else>
          <div v-if="row[prop] && row[prop].length > (countLimit ? countLimit : 50)">
              <el-tooltip effect="dark" :content="row[prop]" placement="top" popper-class="tooltipsCont">
                  <span class="limitInfo">{{row[prop] | textSubstr((countLimit ? countLimit : 50))}}</span>
              </el-tooltip>
          </div>
          <div  v-else>
              <span >{{row[prop] | emptyText}}</span>
          </div>
        </div>
      </template>

      <!-- 如果有多组数据 注: 必传prop  childrenList为数据配置项 -->
      <el-table-column
      v-if="childrenList && childrenList.length > 0"
      v-for="(item, index) in childrenList"
      :label="item.label"
      :key="index"
      :width="width ? width : null"
      :min-width="minWidth ? minWidth : 100"
      align="center">
        <template slot-scope="{row, $index}">
           <!-- 自定义tamplate -->
          <div  v-if="slotName">
            <!-- 插槽传值 data:数组数据 prop:当前数组对象的key index:行索引 -->
            <slot  :name="slotName" :data="prop ? row[prop] : []" :prop="item.prop" :rowData="row" :index="$index"></slot>
          </div>
          <!-- 不是自定义默认遍历数据 row[prop] 获取数组 item.prop为数组配置项的prop -->
          <div v-else >
            <div class="flex-column">
              <div v-for="(dataItem, dataIndex) in row[prop]" :key="dataIndex">
                {{dataItem[item.prop]}}
              </div>
            </div>
          </div>
        </template>
      </el-table-column>
      </el-table-column>
    </el-table>
    <!-- 分页插槽 -->
    <slot name="el-pagination"></slot>
  </div>
</template>
<script>
import { PropsType } from "../propsType.js";
import Sortable from "sortablejs";
export default {
  name: "comm_table",
  data() {
    return {
      lineStyle:{
        'font-size': '14px',
        'height': '45px',
        'padding': '3px 0'
      },
    };
  },
  props: {
    tableData: PropsType.Array,
    tablecolumn: PropsType.Array,
    loading: PropsType.Boolean,//loading
    showExpand: PropsType.Boolean,//是否展示详情行
    selectionObj: PropsType.Object,//是否展示详情行
    height: PropsType.Number,//表格高度
    maxHeight: PropsType.Number,//表格最大高
    tabRef:  PropsType.String,//表格ref
    smallRow: PropsType.Boolean,//控制表格行高
    showHeader: PropsType.Boolean,//是否显示表头
    spanMethod: PropsType.Function,//合并行合并列
    renderHeader: PropsType.Function,//自定义表头
    tabClass: PropsType.String,//表格class [拖动表格需要的参数]
    rowKey: PropsType.String,//表格唯一标识 [拖动表格需要的参数]
    dragTableFlag: PropsType.Boolean,//是否可拖动表格排序 [拖动表格需要的参数]
  },
  watch: {
  },
  methods: {
      sortByKey (column) {//排序
      let params = {}
      if(column.order){
        if (column.column) {
          params.orderBy = column.column.sortBy
          params.desc = column.column.order === 'descending'
          params.order = true;
        }
      }else{//排序恢复
        params.order = false;
      }
      // else {//自定义初始化排序 看情况传入
        //例如
        // params.orderBy = 'avgSales'
        // params.desc = true
      // }
      this.$emit('sortChange', params)
    },
    selectionChange(val) {// 表格checkbox 选择行回调
      this.$emit('selectionChange', val)
    },
    rowDrop() {
      // 此时找到的元素是要拖拽元素的父容器
      const tbody = document.querySelector(`.${this.tabClass} .el-table__body-wrapper tbody`);
      const _this = this;
      Sortable.create(tbody, {
        // 指定父元素下可被拖拽的子元素
        draggable: ".el-table__row",
        onEnd({ newIndex, oldIndex }) {
          if (newIndex !== oldIndex) {
            const currRow = _this.tableData.splice(oldIndex, 1)[0];
            _this.tableData.splice(newIndex, 0, currRow);
            _this.$emit('getDragTableSort', _this.tableData);
          }
        },
      });
    },
  },
  filters: {
    textSubstr (value, qtd = 50, mask = '...') {
      if (!value) return '-';
      return value.length > qtd ? `${value.substring(0, qtd)}${mask}` : value
    },
    emptyText(value){//数据为0的情况显示
      if(value === ''){
	 	  return '-'
	  }
      return value ?? '-'; //或者 (value !== undefined && value !== null) ? vaule : '-'
    }
  },
  mounted() {
    this.dragTableFlag && this.rowDrop();
  },
};
</script>
<style lang="scss">
.tooltipsCont{
  max-width: 500px;
  max-height: 450px;
}
</style>
<style lang="scss" scoped>
.limitInfo{
  cursor: pointer;
}
.flex-column{
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
</style>


组件中使用的 propsType.js

export const PropsType = {
  Array: {
    type: Array,
    default: ()=>([])
  },
  Object: {
    type: Object,
    default: ()=>({})
  },
  Boolean: {
    type: Boolean,
    default: false,
  },
  String: {
    type: String,
    default: ''
  },
  Number: {
    type: Number,
    default: 0
  },
  Function: Function,
  Promise: Promise
}

如何使用CommTable组件【基本展示】

<template>
  <div class="content">
    <div>
      <h1>EC2</h1>
      <CommTable
        tabRef="ec2Table"
        :tableData="tableData"
        :height="450"
        :tablecolumn="tablecolumn"
        :loading="tableLoading"
        :smallRow="true"
        @sortChange="getSortParams"
      >
        <template v-slot:state="{data, index}">
          {{data ? '显示' : '隐藏'}}
        </template>
        <template v-slot:desired="{data, index}">
          {{desiredList.filter(e=>e.value===data)[0].label || '-'}}
        </template>
        <template v-slot:skuProductList="{data, index, prop}">
          <!-- prop是属性 data是当前值 -->
          <div class="flex-column">
            <span v-for="(item, itemIndex) in data" :key="itemIndex">
              {{item[prop]}}
            </span>
          </div>
        </template>
        <template v-slot:operate="{rowData, index}">
          <el-button @click="openEC2Dialog(rowData)" size="mini" type="primary">编辑</el-button>
        </template>
        <el-pagination slot="el-pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="pageNum" :page-sizes="[10, 15, 20, 30, 50]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
        </el-pagination>
      </CommTable>
    </div>
    <EC2Dialog :dialogVisible.sync="ec2visible" :rowObj="selectRow"></EC2Dialog>
  </div>
</template>
<script>
import CommTable from "src/components/partials/CommTable.vue";
import EC2Dialog from './components/editEC2Dialog.vue';
export default {
  name: "operationManagement",
  components: {
    CommTable,
    EC2Dialog
  },
  data() {
    const skuProductColumn = [
        {prop: 'name', label: 'sku'},
        {prop: 'count', label: '数量'},
        {prop: 'price', label: '价格'},
      ];
    return {
      tableData: [],
      tablecolumn: [
        { prop: "id", label: "ID" },
        { prop: "name", label: "名称" },
        { prop: "state", label: "状态" , slotName: 'state'},
        { prop: "instances", label: "实用类型" },
        { prop: 'skuProductList',label: 'sku信息', slotName: 'skuProductList', minWidth: 200, childrenList: skuProductColumn},
        { prop: "privateIPAddres", label: "私有IP地址", sortBy: "privateIPAddres", countLimit: 3, width: 120 },
        { prop: "publicIPAddres", label: "公有IP地址" },
        { prop: "functionDescription", label: "描述" },
        { prop: "desired", label: "预期状态" ,slotName: 'desired'},
        { prop: '', label: '操作', slotName: 'operate',}
      ],
	  desiredList: [
	  	{ value: 'stop', label: '停止' },
        { value: 'delete', label: '删除' },
        { value: 'start', label: '启动' },
      ],
      tableLoading: false,
      ec2visible: false,
      pageSize: 15,
      pageNum: 1,
      total: 0,
      selectRow: {}
    };
  },
  methods: {
    initData() {
      this.tableLoading = true;
      setTimeout(() => {
        this.tableLoading = false;
        this.tableData = [...Array(10).keys()].map((e) => ({
          id: e,
          name: "name" + e,
          state: false,
          instances: "实用类型",
          privateIPAddres: "私有IP地址",
          publicIPAddres: "公有IP地址",
          functionDescription: "描述",
          desired: Math.random() > .5 ? 'stop' : 'delete',
          skuProductList: [
            {name: 'H60523D1', count: 2, price: 39.99},
            {name: 'H60523D2', count: 10, price: 5.99},
          ]
        }));
        this.total = 10
      }, 1000);
    },
    openEC2Dialog(row) {
      this.selectRow = Object.assign({},row);
      console.log(this.selectRow,'selectRow')
      this.ec2visible = true;
    },
    getSortParams(params) {
      console.log("sore", params);
    },
    handleCurrentChange(val) {
      this.pageNum = val;
      this.initData();
    },
    handleSizeChange(val) {
      this.pageSize = val;
      this.pageNum = 1;
      this.initData();
    },
  },
  mounted() {
    this.initData();
  },
};
</script>
<style lang="scss" scoped>
.content {
  padding: 20px;
}
.flex-column{
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
</style>

**column的配置项介绍 **

{ prop, label, width, minWidth ,sortBy, slotName, countLimit, childrenList, className, columnFlag, fixed }
prop: 字段值
label: 显示名称
…宽度
sortBy: 是排序 当有设置的时候 给定一个字符串 然后 就会通过事件返回这个字符串的排序对象参数
slotName : 是自定义字段 有时候表格内容可能需要改动 添加按钮什么的就需要添加这个
countLimit: 字段展示的字符数
childrenList: 数组数据配置 => [{prop:‘字段值’, label:‘表头’}];
className: 给列名添加类名
columnFlag: 区分前后台排序 默认为前台排序 为true时 后台排序
fixed: 定位

 tablecolumn: [
        { prop: "id", label: "ID" },
        { prop: "name", label: "名称" },
        { prop: "state", label: "状态" , slotName: 'state'},
        { prop: "instances", label: "实用类型" },
        { prop: 'skuProductList',label: 'sku信息', slotName: 'skuProductList', minWidth: 200, childrenList: skuProductColumn},
        { prop: "privateIPAddres", label: "私有IP地址", sortBy: "privateIPAddres", countLimit: 3, width: 120 },
        { prop: "publicIPAddres", label: "公有IP地址" },
        { prop: "functionDescription", label: "描述" },
        { prop: "desired", label: "预期状态" ,slotName: 'desired'},
        { prop: '', label: '操作', slotName: 'operate',}
      ],

我调用的时候 有些字段是自定义字段 需要枚举值才可以展示 还有最后的操作按钮

展示一下效果
分页也是可选的 不需要可以不传入插槽就行了
在这里插入图片描述
按钮点击的弹框 事件参数都是可以获取当前表格的值

// 插槽会返回当前插名称 根据插槽名称自定义样式 当前数据 data 如果没有传prop 返回即为空;
当前行数据rowData 和 当前行索引index
//<slot  :name="slotName" :data="prop ? row[prop] : null" :prop="item.prop" :rowData ="row" :index="$index"></slot>
//比如编辑按钮 我们只需要拿到行数据和索引就可以操作你的数据了
 <template v-slot:operate="{rowData, index}">
          <el-button @click="openEC2Dialog(rowData)" size="mini" type="primary">编辑					</el-button>
 </template>

在这里插入图片描述

支持自定义表头功能

两种方法
一: 传递renderHeader方法
在这里插入图片描述
methods里添加方法

renderHeader(h, { column }) {
        switch (column.property) {
          case 'functionDescription':
            return [h('span', {}, [column.label+'这是自定义']), h('el-tooltip', { props: { placement: 'top', effect: 'light' } }, [h('div', { slot: 'content' }, [h('p', {}, ['一个提示'])]), h('i', { class: 'helpTips el-icon-info' ,style: 'cursor:pointer;'})])]
          default:
            return [h('span', {}, [column.label])]
        }
      },

然后查看效果
在这里插入图片描述
二:通过插槽
在这里插入图片描述
这里的是slotName+'Header’的方式 只要定义了slotName然后就可以设置了
在这里插入图片描述
我这里改动的是操作的显示 查看一下效果
在这里插入图片描述
这两种方法都可以改变表头 但是不要一起使用 一起使用会被第一个方法覆盖 插槽就不生效了~

详情内容展示

CommTable组件传入 showExpand true
然后在
在这里插入图片描述
自定义内容就行了

<CommTable
        :tableData="tableData"
        :maxHeight="350"
        :tablecolumn="tablecolumn"
        :showExpand="true"
        :loading="tableLoading"
        :smallRow="true"
        >
        <template v-slot:expand="{data}">
          <span>详情内容{{data}}</span>
        </template>
        <template v-slot:postContent="{data, index}">
          <div style="max-height: 46px;cursor: pointer;" v-clamp v-html="JSON.parse(data).content"></div>
        </template>
        <template v-slot:operate="{rowData, index}">
          <el-button @click="openTimeSelDialog(rowData)" size="mini" type="primary">置顶</el-button>
        </template>
    </CommTable>

效果图
在这里插入图片描述

可拖动表格支持

//表格组件使用插件 sortablejs 自行npm下载依赖
import Sortable from "sortablejs";

使用案例

//template
//需要传入的字段: 
// dragTableFlag: 是否可以拖动 默认false 为true的时候需要传入下面的字段
//rowKey:能唯一确定行的key 
//tabClass: 这个需要给定一个值 如果是多个表格都需要拖动要唯一 
//@getDragTableSort: 为拖动后的回调 返回内容为当前表格数据
<CommTable
        :tableData="tableData"
        :maxHeight="350"
        :tablecolumn="tablecolumn"
        :loading="tableLoading"
        :dragTableFlag="true"
        @getDragTableSort="getDragTableSort"
        rowKey="id"
        :tabClass='`detailClass${rowId}`'
        :smallRow="true"
        >
   </CommTable>
 
 //methods
 getDragTableSort(data){
	console.log(data);//为表格当前排序的值 可以在这里作相应的取值操作或请求
 }

表格复选框选择 及其定位功能

checkbox 回调函数selectionChange
:selectionObj=“{show: true, fixed: true}” 是否显示行复选框 是否定位

 <CommTable
        :tableData="tableData"
        :tablecolumn="tablecolumn"
        :selectionObj="{show: true, fixed: true}"
        ref="tableRef"
        @selectionChange="selectionChange"
        :loading="loading"
        >
 </CommTable>  

效果查看
在这里插入图片描述

  • 8
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在el-table中添加自定义的合计行,你需要进行以下几个步骤: 1. 在el-table中添加合计行的位置。你可以选择将合计行插入到表格数据中的任意位置,例如,在第二行的位置插入合计行(索引为1)。 2. 在表格数据中添加合计行的数据。你可以根据实际需求为合计行添加相应的数据。 3. 在el-table定义合计行的模板。你可以使用<template>标签来定义合计行的样式和内容。 4. 使用计算属性来处理表格数据,并在合适的位置插入合计行的数据。在计算属性中,你可以通过对原始表格数据进行处理,将合计行的数据插入到正确的位置。 下面是一个示例代码,演示了如何在el-table中添加自定义的合计行: ``` <template> <el-table :data="computedTableData"> <el-table-column type="index" label="序号" width="80"></el-table-column> <el-table-column prop="name" label="姓名"></el-table-column> <el-table-column prop="age" label="年龄"></el-table-column> <el-table-column prop="score" label="分数"></el-table-column> <!-- 添加合计行的模板 --> <template slot="append"> <el-table-column label="合计"> <template slot-scope="scope"> {{ getTotal(scope.$index) }} </template> </el-table-column> </template> </el-table> </template> <script> export default { data() { return { tableData: [ { name: '张三', age: 18, score: 80 }, { name: '李四', age: 20, score: 90 }, { name: '王五', age: 22, score: 85 } ] }; }, computed: { computedTableData() { let totalRow = { name: '合计', age: 0, score: 0 }; // 在合适的位置插入合计行的数据 this.tableData.splice(1, 0, totalRow); return this.tableData; } }, methods: { getTotal(index) { // 计算合计值 let total = 0; for (let i = 0; i < this.tableData.length; i++) { total += this.tableData[i].score; } return total; } } }; </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值